iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0

我們已經示範過附加新的Metadata,那今天的目標是建立User Metadata,因為有些時候DeepStream設計的Metadata不能滿足應用的需求,特別是應用有需要寫自訂元件的時候,往往會需要額外的資料來完成目標。

範例程式

main.c

我們複製Day 20的程式進行修改

[...]
#define PGIE_UNIQUE_ID 1
#define PERSON_CLASS_ID 2
#define IRONMAN_UNIQUE_ID 9

#define IRONMAN_YEAR 2026
#define IRONMAN_DAY 21

typedef struct {
    guint year;
    guint day;
} IronmanMeta;

#define IRONMAN_META nvds_get_user_meta_type("IRONMAN.DEEPSTREAM.META")

static IronmanMeta* ironman_meta_new(guint year, guint day) {
    IronmanMeta* meta = g_malloc0(sizeof(IronmanMeta));
    meta->year = year;
    meta->day = day;
    return meta;
}

static gpointer ironman_meta_copy_func(gpointer data, gpointer user_data) {
    (void)user_data;

    NvDsUserMeta* user_meta = data;
    IronmanMeta* src = user_meta->user_meta_data;
    IronmanMeta* copy = g_malloc0(sizeof(IronmanMeta));
    *copy = *src;

    return copy;
}

static void ironman_meta_release_func(gpointer data, gpointer user_data) {
    (void)user_data;

    NvDsUserMeta* user_meta = data;
    /* The argument of g_free can be NULL */
    g_free(user_meta->user_meta_data);
}

[...]

static NvDsUserMeta* create_ironman_meta(NvDsBatchMeta* batch_meta) {
    NvDsUserMeta* user_meta = nvds_acquire_user_meta_from_pool(batch_meta);
    if (!user_meta) {
        g_print("WARNING: Can't acquire meta data from pool\n");
        return NULL;
    }

    IronmanMeta* ironman_meta = ironman_meta_new(IRONMAN_YEAR, IRONMAN_DAY);
    user_meta->user_meta_data = ironman_meta;
    user_meta->base_meta.meta_type = IRONMAN_META;
    user_meta->base_meta.copy_func = ironman_meta_copy_func;
    user_meta->base_meta.release_func = ironman_meta_release_func;

    return user_meta;
}

static GstPadProbeReturn handle_osd_sink_pad_probe(GstPad*, GstPadProbeInfo* info, gpointer) {
    /* 'buf' is owned by 'info', we don't need to release it */
    GstBuffer* buf = gst_pad_probe_info_get_buffer(info);

    /* gst_pad_probe_info_get_buffer may return NULL */
    if (!buf) {
        g_print("WARNING: Can't get GstBuffer from GstPadProbeInfo\n");
        return GST_PAD_PROBE_OK;
    }

    NvDsBatchMeta* batch_meta = gst_buffer_get_nvds_batch_meta(buf);
    if (!batch_meta) {
        g_print("WARNING: No NvDsBatchMeta was attched on the GstBuffer\n");
        return GST_PAD_PROBE_OK;
    }

    for (NvDsFrameMetaList* l_frame = batch_meta->frame_meta_list; l_frame; l_frame = l_frame->next) {
        NvDsFrameMeta* frame_meta = l_frame->data;

        for (NvDsObjectMetaList* l_obj = frame_meta->obj_meta_list; l_obj; l_obj = l_obj->next) {
            NvDsObjectMeta* obj_meta = l_obj->data;
            if (obj_meta->unique_component_id == PGIE_UNIQUE_ID
                && obj_meta->class_id == PERSON_CLASS_ID) {
                NvDsClassifierMeta* class_meta = create_classifier_meta(batch_meta, "ironman");
                NvDsUserMeta* user_meta = create_ironman_meta(batch_meta);

                /* Must lock 'batch_meta' when modifying existing metadata */
                nvds_acquire_meta_lock(batch_meta);
                nvds_add_classifier_meta_to_object(obj_meta, class_meta);
                nvds_add_user_meta_to_obj(obj_meta, user_meta);
                object_meta_refresh_label(obj_meta);
                nvds_release_meta_lock(batch_meta);
            }
        }
    }

    return GST_PAD_PROBE_OK;
}

範例解說

定義結構、copy_func、release_func

typedef struct {
    guint year;
    guint day;
} IronmanMeta;

#define IRONMAN_META nvds_get_user_meta_type("IRONMAN.DEEPSTREAM.META")

static IronmanMeta* ironman_meta_new(guint year, guint day) {
    IronmanMeta* meta = g_malloc0(sizeof(IronmanMeta));
    meta->year = year;
    meta->day = day;
    return meta;
}

static gpointer ironman_meta_copy_func(gpointer data, gpointer user_data) {
    (void)user_data;

    NvDsUserMeta* user_meta = data;
    IronmanMeta* src = user_meta->user_meta_data;
    IronmanMeta* copy = g_malloc0(sizeof(IronmanMeta));
    *copy = *src;

    return copy;
}

static void ironman_meta_release_func(gpointer data, gpointer user_data) {
    (void)user_data;

    NvDsUserMeta* user_meta = data;
    /* The argument of g_free can be NULL */
    g_free(user_meta->user_meta_data);
}

NvDsMetaType先前有介紹過了,這邊就是實際示範一次,增加大家的印象。主要就是得定義一個struct來儲存我們需要的資料,實例化(ironman_meta_new)則是為了方便直接採用g_malloc0,如果要進一步優化就是使用自己的Object Pool或是Allocator,搭配NvDsUserMeta的uContext使用。

建立NvDsUserMeta

static NvDsUserMeta* create_ironman_meta(NvDsBatchMeta* batch_meta) {
    NvDsUserMeta* user_meta = nvds_acquire_user_meta_from_pool(batch_meta);
    if (!user_meta) {
        g_print("WARNING: Can't acquire meta data from pool\n");
        return NULL;
    }

    IronmanMeta* ironman_meta = ironman_meta_new(IRONMAN_YEAR, IRONMAN_DAY);
    user_meta->user_meta_data = ironman_meta;
    user_meta->base_meta.meta_type = IRONMAN_META;
    user_meta->base_meta.copy_func = ironman_meta_copy_func;
    user_meta->base_meta.release_func = ironman_meta_release_func;

    return user_meta;
}

NvDsUserMeta一樣是從batch_meta的Pool取得,user_meta_data放上我們自訂的資料,最重要的就是base_meta的meta_type、copy_func、release_func要記得填寫

附加NvDsUserMeta

NvDsClassifierMeta* class_meta = create_classifier_meta(batch_meta, "ironman");
NvDsUserMeta* user_meta = create_ironman_meta(batch_meta);

/* Must lock 'batch_meta' when modifying existing metadata */
nvds_acquire_meta_lock(batch_meta);
nvds_add_classifier_meta_to_object(obj_meta, class_meta);
nvds_add_user_meta_to_obj(obj_meta, user_meta);
object_meta_refresh_label(obj_meta);
nvds_release_meta_lock(batch_meta);

跟其他Metadata一樣可以找到對應的附加函式,不過NvDsUserMeta可以附加在幾乎所有的Metadata上,依照需求找一個合理的位置附加上去才是正確的

結語

雖然DeepStream提供了NvDsUserMeta來應付自定義資料的需求,可是實際開發中有很多SDK設計好的函式簽章是不會帶入NvDsUserMeta參數的,說真的用起來也是綁手綁腳,這也就衍伸出這系列最重的目標,為什麼我們需要自己建立GStreamer元件


上一篇
[Day 20] 如何附加新的Meta Data
下一篇
[Day 22] 實作GStreamer插件的優勢
系列文
深入認識DeepStream,不只是停在執行範例 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言